let SUN = ({});
SUN.extend = function(name, val) { SUN[name] = val;};
SUN.extend("default", function(e){
	e.x = 0;
	e.y = 0;
	e.rotation = 0;
	e.scaleX = 1;
	e.scaleY = 1;
	e.alpha = 1;
	e.visible = true;
	e.blend = "source-over";
	e.frameTime = 0;
	e.mouseEnabled = true;
	e.event = {};
});

window.requestAnimFrame = (function(callback) {
	return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
	function(callback) {
		window.setTimeout(callback, 1000 / 60);
	};
})();

window.cancelAnimFrame = (function(id) {
	return window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.oCancelAnimationFrame || window.msCancelAnimationFrame ||
	function(id) {
		window.clearTimeout(id);
	};
})();


// 舞台类
SUN.Stage = function(id) {
	
	var _this = this;
	_this.canvas = document.getElementById(id);
	_this.context = _this.canvas.getContext("2d");
	_this.stageWidth = _this.canvas.width;
	_this.stageHeight = _this.canvas.height;
	_this.displayObjects = [];
	_this.tweenObjects = [];
	_this.events = {};
	_this.play = true;
	_this.numChild = 0;
	
	// 舞台添加侦听
	_this.addEventListener = function(type, callback) {
		if (type == "added") {
			if (_this.canvas && _this.context) {
				callback();
			}
		} else {
			_this.canvas.addEventListener(type, callback, false);
		}
	}

	// 舞台删除侦听
	_this.removeEventListener = function(type, callback) {
		_this.canvas.removeEventListener(type, callback, false);
	}

	// 原件侦听器
	_this.mouseEvent = function(e) {
		var s = _this.canvas.width / _this.canvas.clientWidth;
		var _px = (e["changedTouches"] ? e["changedTouches"][0].pageX : e.pageX) * s;
		var _py = (e["changedTouches"] ? e["changedTouches"][0].pageY : e.pageY) * s;
        for (var i = _this.displayObjects.length - 1; i >= 0; i--) {
        	var _i = _this.displayObjects[i];
        	if (_i.hitTestPoint(_px, _py)) {
	        	if (_i.event[e.type] != null && _i.mouseEnabled) {
                	_i.event[e.type].apply(_i, [e]);
                }
                return;
            }
        }
	}

	// 添加子对象
	_this.addChild = function(child) {
		if (child instanceof SUN.MovieClip || child instanceof SUN.Layer){
			child.parentStage = _this;
			if (_this.indexOf(child) == -1) {
				_this.displayObjects.push(child);
			} else {
				_this.displayObjects.splice(_this.indexOf(child), 1);
				_this.displayObjects.push(child);
			}
			_this.numChild = _this.displayObjects.length;
		}
	}

	// 添加带深度的子对象
	_this.addChildAt = function(child, index) {
		if (child instanceof SUN.MovieClip || child instanceof SUN.Layer){
			child.parentStage = _this;
			if (_this.indexOf(child) == -1) {
				_this.displayObjects.splice(index, 0, child);
			} else {
				_this.displayObjects.splice(_this.indexOf(child), 1);
				_this.displayObjects.splice(index, 0, child);
			}
			_this.numChild = _this.displayObjects.length;
		}
	}
	
	// 删除子对象
	_this.removeChild = function(child) {
		if (_this.indexOf(child) != -1) {
			child._remove_ = true;
		}
	}

	// 删除所有对象
	_this.removeAllChild = function(){
		_this.displayObjects = [];
	}
	
	// 删除目标深度的子对象
	_this.removeChildAt = function(index) {
		if (index >= 0 && index < _this.numChild) {
			_this.displayObjects[index]._remove_ = true;
		}
	}

	// 设置对象的深度
	_this.setChildIndex = function(child, index) {
		if (_this.indexOf(child) != -1) {
			_this.displayObjects.splice(_this.indexOf(child), 1);
			_this.displayObjects.splice(index, 0, child);
		}
	}

	// 获得对象的深度
	_this.getChildIndex = function(child) {
		if (_this.indexOf(child) != -1) {
			return _this.indexOf(child);
		}
	}
	
	// 查询对象是否在数组中
	_this.indexOf = function(object) {
		for (var i = 0; i < _this.displayObjects.length; i++) {
			if (_this.displayObjects[i] == object) {
				return i;
			}
		}
		return -1;
	}
	
	// 重绘
	_this.redraw = function() {
		if (_this.play) {
			// 重绘所有元素
			_this.paint();
		}
		// 重新循环绘画
		requestAnimFrame(_this.redraw);
	}

	// 停止画布所有动画
	_this.kill = function() {
		_this.play = false;
		_this.redraw = function(){};
	}

	// 停止后的恢复
	_this.replay = function(){
		if (!_this.play) {
			_this.play = true;
			_this.redraw = function() {
				if (_this.play) {
					_this.paint();
				}
				requestAnimFrame(_this.redraw);
			}
			_this.redraw();
		}
	}


	// 动画重绘函数
	_this.paint = function() {

		// 清空画布
		_this.context.clearRect(0, 0, _this.stageWidth, _this.stageHeight);

		if (_this.numChild != 0) {
			// 重绘所有元素
			for (var i = 0; i < _this.numChild; i++) {

				if (i < 0) { return false;}
				var data = _this.displayObjects[i];				
				if (data instanceof SUN.MovieClip && data.visible) {
					// 如果对象已经被删除
					if (data._remove_ == true) {
						_this.displayObjects.splice(i, 1);
						_this.numChild = _this.displayObjects.length;
						i--;
					} else {
						_this.paintData(data);
					}
				} else if (data instanceof SUN.Layer && data.visible) {
					for (var j = 0; j < data.numChild; j++) {
						var ldata = data.displayObjects[j];
						if (ldata instanceof SUN.MovieClip && ldata.visible) {
							// 如果对象已经被删除
							if (ldata._remove_ == true) {
								data.displayObjects.splice(j, 1);
								data.numChild = data.displayObjects.length;
								j--;
							} else {
								_this.paintData(ldata);
							}
						}
					}
				}
			}
		}
	}

	// 重绘
	_this.paintData = function(data) {

		// 更新动画状态
		if (data.loop) {
			// 因为canvas动画最高的帧数是60,所以用分频的做法去算设置过fps的动画
			if (data.fps != undefined && data.fps != 0 && data.fps < 60) {
				if (data.__fps__c__ == undefined) {
					data.__fps__c__ = 0;
				} else {
					data.__fps__c__ ++;
				}
				if (60 - data.fps == data.__fps__c__) {
					data.loop();
					data.__fps__c__ = 0;
				}
			} else {
				data.loop();
			}
		}

		// 如果在缓动运动中更新状态
		if (data.isTweening == true && data._tweenObj_) {
			data._tweenObj_.run++;
			if (data._tweenObj_.run / 60  < data._tweenObj_.time) {
				var _p = data._tweenObj_.run / 60 / data._tweenObj_.time;
				SUN.setTweenVal(data._tweenObj_, _p);
			} else {
				SUN.setTweenVal(data._tweenObj_, 1);
				delete data.isTweening;
				if (data._tweenObj_.object.callback) {
					var cb = data._tweenObj_.object.callback;
					delete data._tweenObj_;
					cb(data);
				} else {
					delete data._tweenObj_;
				}
			}
		}

		data.alpha = data.alpha > 1 ? 1 : data.alpha < 0 ? 0 : data.alpha;
		data.scaleX = data.scaleX < 0 ? 0 : data.scaleX;
		data.scaleY = data.scaleY < 0 ? 0 : data.scaleY;

		if (data.alpha == undefined || data.alpha == 0){
			// 如果该mc没有透明度或者为0,更新数据即可,不在画布上画该mc，因为画了也看不见
			return;
		}

		// 保存画布句柄状态
		_this.context.save();

		//加入混色功能
		_this.context.globalCompositeOperation = data.blend;

		// 改变画布的透明度
		_this.context.globalAlpha = data.alpha;
		
		// 设置画布的坐标
		_this.context.translate(data.x, data.y);

		// 设置画布的旋转角度
		_this.context.rotate(data.rotation * Math.PI / 180);

		// 设置画布的缩放
		
		_this.context.scale(data.scaleX, data.scaleY);

		// 画布参数设置好之后绘入
		if (data.draw) {
			data.draw.apply(_this.context, [data]);
		}

		// 显示对象范围
		// if (data.range) {
		// 	_this.context.beginPath();
		// 	_this.context.fillStyle = "rgba(0,255,200,0.4)";
		// 	_this.context.rect(data.range.x, data.range.y, data.range.width, data.range.height);
		// 	_this.context.fill();
		// 	_this.context.closePath();
		// }

		// 还原画布
		_this.context.restore();
	} 

	// 循环开始
	_this.redraw();

}

// 影片类
SUN.MovieClip = function() {
	var _this = this;
	SUN.default(_this);
	_this.getVars = function() {
		var e = {};
		e.x = _this.x;
		e.y = _this.y;
		e.rotation = _this.rotation;
		e.scaleX = _this.scaleX;
		e.scaleY = _this.scaleY;
		e.alpha = _this.alpha;
		return e;
	}
	_this.addEventListener = function(type, callback) {
		if (_this.range && _this.event[type] == null) {
			_this.event[type] = callback;
			_this.parentStage.events[type] = _this.parentStage.events[type] ? _this.parentStage.events[type] + 1 : 1;
			if (_this.parentStage.events[type] == 1) {
				_this.parentStage.canvas.addEventListener(type, _this.parentStage.mouseEvent);
			}
		}
	}
	_this.removeEventListener = function(type) {
		if (_this.event[type] != null) {
			_this.event[type] = null;
			_this.parentStage.events[type] = _this.parentStage.events[type] > 0 ? _this.parentStage.events[type] - 1 : 0;
			if (_this.parentStage.events[type] == 0) {
				_this.parentStage.canvas.removeEventListener(type, _this.parentStage.mouseEvent);
			}
		}
	}
	// 缓动子对象
	_this.tween = function(time, object) {
		if (_this.isTweening != true) {
			object.ease = object.ease ? object.ease : "easeInQuad";
			_this.isTweening = true;
			_this._tweenObj_ = {"child": _this, "time": time, "object": object, "default": _this.getVars(), "run": 0};

			var _tween = {"child": _this, "time": time, "object": object, "default": _this.getVars(), "start": 0};
			_this.parentStage.tweenObjects.push(_tween);
		}
	}
	_this.setRange = function(range) {
		if (range && range.x != null && range.y != null && range.width && range.height) {
			_this.rangeType = "rect";
			_this.range = range;
		}
	}
	_this.hitTestObject = function(child) {
		if (child && _this.range && _this.rangeType && child.visible && child.range && child.rangeType && _this.parentStage.indexOf(child) != -1) {
			var _objects = [_this, child];
			for (var i = 0; i < _objects.length; i++) {
				var _range = SUN.getRangePoint(_objects[i]);
				for (var j in _range) {
					if (i == 0) {
						if (child.hitTestPoint(_range[j][0], _range[j][1])) {
							return true;
						}
					} else if (i == 1) {
						if (_this.hitTestPoint(_range[j][0], _range[j][1])) {
							return true;
						}
					}
				}
			}
		}
		return false;
	}
	_this.hitTestPoint = function(x, y) {
		// 缩放有bug待修复，缩放后判断不准确
		if (_this.range && _this.rangeType) {
        	if (_this.x + _this.range.x <= x && _this.x + _this.range.x + _this.range.width >= x && _this.y + _this.range.y <= y && _this.y + _this.range.y + _this.range.height >= y) {
                return true;
            } else {
            	return false;
            }
        }
	}
}


// 设置缓动动画数据
SUN.extend("setTweenVal", function(val, progress) {
	for (var i in val.object) {
		if (typeof val.object[i] == "number" && val.default[i] != null && val.object[i] != null) {
			val.child[i] = val.default[i] + (val.object[i] - val.default[i]) * SUN.tweens[val.object.ease](progress);
		}
	}
});

// 获取对象区域的四个坐标
SUN.extend("getRangePoint", function(child){
	if (child.range) {
		var _p = {};
		var _rotate = Math.PI / 180 * (child.rotation + 90);
		var _sin = Math.sin(_rotate);
		var _cos = Math.cos(_rotate);
		_sin = 1;
		_cos = 1;
		_p.p1 = [_sin * (child.x + child.range.x), _cos * (child.y + child.range.y)];
		_p.p2 = [_sin * (child.x + child.range.x + child.range.width), _cos * (child.y + child.range.y)];
		_p.p3 = [_sin * (child.x + child.range.x), _cos * (child.y + child.range.y + child.range.height)];
		_p.p4 = [_sin * (child.x + child.range.x + child.range.width), _cos * (child.y + child.range.y + child.range.height)];
		return _p;
	} else {
		return false;
	}
});

// 缓动方法
SUN.extend("tweens", {
	easeInQuad: function(pos) {
        return Math.pow(pos, 2);
    },
    easeOutQuad: function(pos) {
        return - (Math.pow((pos - 1), 2) - 1);
    },
    easeInOutQuad: function(pos) {
        if ((pos /= 0.5) < 1) return 0.5 * Math.pow(pos, 2);
        return - 0.5 * ((pos -= 2) * pos - 2);
    },
    easeInCubic: function(pos) {
        return Math.pow(pos, 3);
    },
    easeOutCubic: function(pos) {
        return (Math.pow((pos - 1), 3) + 1);
    },
    easeInOutCubic: function(pos) {
        if ((pos /= 0.5) < 1) return 0.5 * Math.pow(pos, 3);
        return 0.5 * (Math.pow((pos - 2), 3) + 2);
    },
    easeInQuart: function(pos) {
        return Math.pow(pos, 4);
    },
    easeOutQuart: function(pos) {
        return - (Math.pow((pos - 1), 4) - 1)
    },
    easeInOutQuart: function(pos) {
        if ((pos /= 0.5) < 1) return 0.5 * Math.pow(pos, 4);
        return - 0.5 * ((pos -= 2) * Math.pow(pos, 3) - 2);
    },
    easeInQuint: function(pos) {
        return Math.pow(pos, 5);
    },
    easeOutQuint: function(pos) {
        return (Math.pow((pos - 1), 5) + 1);
    },
    easeInOutQuint: function(pos) {
        if ((pos /= 0.5) < 1) return 0.5 * Math.pow(pos, 5);
        return 0.5 * (Math.pow((pos - 2), 5) + 2);
    },
    easeInSine: function(pos) {
        return - Math.cos(pos * (Math.PI / 2)) + 1;
    },
    easeOutSine: function(pos) {
        return Math.sin(pos * (Math.PI / 2));
    },
    easeInOutSine: function(pos) {
        return ( - .5 * (Math.cos(Math.PI * pos) - 1));
    },
    easeInExpo: function(pos) {
        return (pos == 0) ? 0 : Math.pow(2, 10 * (pos - 1));
    },
    easeOutExpo: function(pos) {
        return (pos == 1) ? 1 : -Math.pow(2, -10 * pos) + 1;
    },
    easeInOutExpo: function(pos) {
        if (pos == 0) return 0;
        if (pos == 1) return 1;
        if ((pos /= 0.5) < 1) return 0.5 * Math.pow(2, 10 * (pos - 1));
        return 0.5 * ( - Math.pow(2, -10 * --pos) + 2);
    },
    easeInCirc: function(pos) {
        return - (Math.sqrt(1 - (pos * pos)) - 1);
    },
    easeOutCirc: function(pos) {
        return Math.sqrt(1 - Math.pow((pos - 1), 2))
    },
    easeInOutCirc: function(pos) {
        if ((pos /= 0.5) < 1) return - 0.5 * (Math.sqrt(1 - pos * pos) - 1);
        return 0.5 * (Math.sqrt(1 - (pos -= 2) * pos) + 1);
    },
    easeOutBounce: function(pos) {
        if ((pos) < (1 / 2.75)) {
            return (7.5625 * pos * pos);
        } else if (pos < (2 / 2.75)) {
            return (7.5625 * (pos -= (1.5 / 2.75)) * pos + .75);
        } else if (pos < (2.5 / 2.75)) {
            return (7.5625 * (pos -= (2.25 / 2.75)) * pos + .9375);
        } else {
            return (7.5625 * (pos -= (2.625 / 2.75)) * pos + .984375);
        }
    },
    easeInBack: function(pos) {
        var s = 1.70158;
        return (pos) * pos * ((s + 1) * pos - s);
    },
    easeOutBack: function(pos) {
        var s = 1.70158;
        return (pos = pos - 1) * pos * ((s + 1) * pos + s) + 1;
    },
    easeInOutBack: function(pos) {
        var s = 1.70158;
        if ((pos /= 0.5) < 1) return 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s));
        return 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2);
    },
    elastic: function(pos) {
        return - 1 * Math.pow(4, -8 * pos) * Math.sin((pos * 6 - 1) * (2 * Math.PI) / 2) + 1;
    },
    swingFromTo: function(pos) {
        var s = 1.70158;
        return ((pos /= 0.5) < 1) ? 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s)) : 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2);
    },
    swingFrom: function(pos) {
        var s = 1.70158;
        return pos * pos * ((s + 1) * pos - s);
    },
    swingTo: function(pos) {
        var s = 1.70158;
        return (pos -= 1) * pos * ((s + 1) * pos + s) + 1;
    },
    bounce: function(pos) {
        if (pos < (1 / 2.75)) {
            return (7.5625 * pos * pos);
        } else if (pos < (2 / 2.75)) {
            return (7.5625 * (pos -= (1.5 / 2.75)) * pos + .75);
        } else if (pos < (2.5 / 2.75)) {
            return (7.5625 * (pos -= (2.25 / 2.75)) * pos + .9375);
        } else {
            return (7.5625 * (pos -= (2.625 / 2.75)) * pos + .984375);
        }
    },
    bouncePast: function(pos) {
        if (pos < (1 / 2.75)) {
            return (7.5625 * pos * pos);
        } else if (pos < (2 / 2.75)) {
            return 2 - (7.5625 * (pos -= (1.5 / 2.75)) * pos + .75);
        } else if (pos < (2.5 / 2.75)) {
            return 2 - (7.5625 * (pos -= (2.25 / 2.75)) * pos + .9375);
        } else {
            return 2 - (7.5625 * (pos -= (2.625 / 2.75)) * pos + .984375);
        }
    },
    easeFromTo: function(pos) {
        if ((pos /= 0.5) < 1) return 0.5 * Math.pow(pos, 4);
        return - 0.5 * ((pos -= 2) * Math.pow(pos, 3) - 2);
    },
    easeFrom: function(pos) {
        return Math.pow(pos, 4);
    },
    easeTo: function(pos) {
        return Math.pow(pos, 0.25);
    },
    linear: function(pos) {
        return pos
    },
    sinusoidal: function(pos) {
        return ( - Math.cos(pos * Math.PI) / 2) + 0.5;
    },
    reverse: function(pos) {
        return 1 - pos;
    },
    flicker: function(pos) {
        var pos = pos + (Math.random() - 0.5) / 5;
        return SUN.tweens.sinusoidal(pos < 0 ? 0 : pos > 1 ? 1 : pos);
    },
    wobble: function(pos) {
        return ( - Math.cos(pos * Math.PI * (9 * pos)) / 2) + 0.5;
    },
    spring: function(pos) {
        return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp( - pos * 6));
    },
    none: function(pos) {
        return 0
    },
    full: function(pos) {
        return 1
    }
});


export default SUN